# -*- coding: utf-8 -*-
from openerp.osv import fields
from openerp.osv import osv
from openerp import SUPERUSER_ID
import datetime, time
from openerp import models, SUPERUSER_ID
import openerp.addons.decimal_precision as dp
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT, float_compare
from openerp.http import request
import calendar
import copy
import StringIO
import base64
import xlwt
from datetime import timedelta
from dateutil.relativedelta import relativedelta
ISODATETIMEFORMAT = "%Y-%m-%d %H:%M:%S"
ISODATEFORMAT = '%Y-%m-%d'


class daily_count(osv.osv):
    _name = 'daily.count'

    def _compute_result(self, cr, uid, ids, name, args, context=None):
        """ 要把本天的所有的信息进行整合，合并成一条方便生成最后的报表"""
        res = {}
        for daily_row in self.browse(cr, uid, ids, context=context):
            result_list = [daily_row.late_hours or u'上班无记录', daily_row.leave_early or u'下班无记录',
                           daily_row.leave_time, daily_row.off_time, daily_row.fill_card,
                           daily_row.punch_line_time]

            result_message = '\n'.join([str(result) for result in result_list if result != '0']) or ''
            if u'上班未打卡' in result_message and u'下班未打卡' in result_message and daily_row.leave_time == '0' and \
                daily_row.off_time == '0' and daily_row.punch_line_time == '0' and daily_row.fill_card == '0' and \
                    datetime.datetime.strptime('%s 01:01:01' % daily_row.date, "%Y-%m-%d %H:%M:%S").weekday() in [5, 6]:
                    result_message = u'休息\n'
            elif u'上班打卡正常' in result_message and u'下班打卡正常' in result_message:
                result_message = u'正常'
            res[daily_row.id] = result_message
        return res

    _columns = {
        'user_id': fields.many2one('res.users', u'用户'),
        'date': fields.date(u'日期'),
        'late_hours': fields.char(u'上班打卡详情'),
        'leave_early': fields.char(u'下班打卡详情'),
        'leave_time': fields.char(u'请假详情'),
        'off_time': fields.char(u'调休调休详情'),
        'punch_line_time': fields.char(u'外勤打卡详情'),
        'fill_card': fields.char(u'补卡详情'),
        'daily_state': fields.selection([('normal', u'正常'), ('abnormal', u'异常')], u'状态'),
        'result_message': fields.function(_compute_result, type='text', store=True, string='最终结果')
    }

    _defaults = {
        'late_hours': 0,
        'leave_early': 0,
        'leave_time': 0,
        'off_time': 0,
        'fill_card': 0,
        'punch_line_time': 0
    }


class create_daily_count_wizard(models.TransientModel):
    _name = 'create.daily.count.wizard'
    _columns = {
        'begin_date': fields.date(u'开始时间'),
        'end_date': fields.date(u'结束时间'),
    }
    _defaults = {
        'begin_date': False,
        'end_date': False,
    }

    def create_daily_count(self, cr, uid, ids, context=None):
        """创建 每天的考勤统计的。"""
        punch_obj = self.pool.get('weixin.punch')
        approval_obj = self.pool.get('weixin.approval')
        daily_obj = self.pool.get('daily.count')
        contacts_obj = self.pool.get('weixin.contacts')
        contacts_ids = contacts_obj.search(cr, uid, [('is_disabled', '=', False)], context=context)
        for row in self.browse(cr, uid, ids, context=context):
            punch_obj.get_today_punch_record(cr, uid, some_start_date="%s 00:00:00" % row.begin_date,
                                                      some_end_date='%s 23:59:59' % row.end_date, context=context)
            approval_obj.get_all_approval_data(cr, uid, input_start_time="%s 00:00:00" % row.begin_date,
                                                        input_end_time='%s 23:59:59' % row.end_date, context=context)
            begin_date = datetime.datetime.strptime(row.begin_date, ISODATEFORMAT)
            end_date = datetime.datetime.strptime(row.end_date, ISODATEFORMAT)
            daily_ids = daily_obj.search(cr, uid, [ ('date', '>=', row.begin_date),
                ('date', '<=', row.end_date)], context=context)
            daily_obj.unlink(cr, uid, daily_ids, context=context)
            daily_count_dict = {}
            for num in range((end_date - begin_date).days + 1):
                for contact_row in contacts_obj.browse(cr, uid, contacts_ids, context=context):
                    contact_user_id = contact_row.odoo_user_id.id
                    date_str = (begin_date + relativedelta(days=num)).strftime(ISODATEFORMAT)
                    update_val = {'user_id': contact_user_id,
                                  'date': date_str,
                                  'late_hours': u'上班未打卡',
                                  'leave_early': u'下班未打卡'}

                    update_val.update(self.get_leave_time_result(cr, uid, date_str, contact_row.id, context=context))
                    update_val.update(self.get_off_time_result(cr, uid, date_str, contact_user_id, context=context))
                    punch_ids = punch_obj.search(cr, uid, [('date', '>=', self.str_date_to_utcdate("%s 00:00:00" % date_str)),
                                                           ('userid', '=', contact_row.id),
                                                           ('date', '<=', "%s 20:59:59" % date_str)], context=context)
                    for punch_row in punch_obj.browse(cr, uid, punch_ids, context=context):
                        update_val.update(
                            self.get_punch_result(cr, uid, punch_row, daily_count_dict, date_str, context=context))
                    copy_update_val = copy.deepcopy(update_val)
                    daily_count_dict.update({(date_str, contact_user_id): copy_update_val})
            for key, value in daily_count_dict.iteritems():
                daily_obj.create(cr, uid, value, context=context)
        return True

    def str_utcdate_to_date(self, date_str):
        """
        UTC 时间字符串 转换成 东8 区的时区的字符串
        :param date_str: 日期字符串。
        :return:
        """
        timeArray = time.localtime((time.mktime(time.strptime(date_str, '%Y-%m-%d %H:%M:%S')) + 8 * 3600))
        punch_row_date = time.strftime("%Y-%m-%d %H:%M:%S", timeArray)
        return punch_row_date

    def str_date_to_utcdate(self, date_str):
        """
        UTC 时间字符串 转换成 东8 区的时区的字符串
        :param date_str: 日期字符串。
        :return:
        """
        timeArray = time.localtime((time.mktime(time.strptime(date_str, '%Y-%m-%d %H:%M:%S')) - 8 * 3600))
        punch_row_date = time.strftime("%Y-%m-%d %H:%M:%S", timeArray)
        return punch_row_date


    def get_off_time_result(self, cr, uid, date_str, apply_user_id, context=None):
        """搜索指定打卡记录所在的日期的 调休的情况"""
        update_val = {}
        overtime_obj = self.pool.get('work.overtime.leave')
        start_date_str = "%s 00:00:00" % date_str
        end_date_str = '%s 23:59:59' % date_str
        overtime_ids = overtime_obj.search(cr, uid, [('user_id', '=', apply_user_id),
                                                     ('type', '=', 'changeworkday'),
                                                     ('is_approve', '=', True),
                                                     '|', '|', '&', ('start_time', '<=', start_date_str),
                                                     ('end_time', '>', start_date_str),
                                                     '&', ('start_time', '<', end_date_str),
                                                     ('end_time', '>=', end_date_str),
                                                     '&', ('start_time', '>', start_date_str),
                                                     ('end_time', '<', end_date_str),
                                                     ],
                                           context=context)
        all_hour_qty = 0
        for overtime_row in overtime_obj.browse(cr, uid, overtime_ids, context=context):
            all_hour_qty += overtime_row.hour_qty
        if all_hour_qty:
            update_val.update({'off_time': u'调休总时长%s' % all_hour_qty})
        return copy.deepcopy(update_val)

    def get_leave_time_result(self, cr, uid, date_str, apply_user_id,context=None):
        """根据打卡记录的时间 获取请假的详细的情况"""
        leave_list = [u'年假', u'事假', u'病假', u'调休假', u'婚假', u'产假', u'陪产假', u'其他', u'补卡', u'外出']
        update_val = {}
        approval_obj = self.pool.get('weixin.approval')
        start_date_str = "%s 00:00:00" % date_str
        end_date_str = '%s 23:59:59' % date_str
        approval_ids = approval_obj.search(cr, uid, [('apply_user_id', '=', apply_user_id),
                                                     '|',  '|', '|', '|',
                                                     '&', ('start_datetime', '<=', start_date_str),
                                                     ('end_datetime', '>', start_date_str),
                                                     '&', ('start_datetime', '<', end_date_str),
                                                     ('end_datetime', '>=', end_date_str),
                                                     '&', ('start_datetime', '>', start_date_str),
                                                     ('end_datetime', '<', end_date_str),
                                                     '&', ('start_datetime', '=', False),
                                                     '&', ('end_datetime', '>', start_date_str),
                                                     ('end_datetime', '<', end_date_str),
                                                     '&', ('start_datetime', '>', start_date_str),
                                                     '&', ('start_datetime', '<', end_date_str),
                                                     ('end_datetime', '=', False),
                                                     ],
                                           context=context)
        leave_all_hours, fill_card_hours = 0, ''
        leave_type_str = ''
        for approval_row in approval_obj.browse(cr, uid, approval_ids, context=context):
            if approval_row.leave_type != 9 and approval_row.leave_type:
                leave_type_str += leave_list[approval_row.leave_type - 1]
                leave_all_hours += round(float(approval_row.duration), 2)
            elif approval_row.leave_type:
                if approval_row.start_datetime:
                    fill_card_hours += '上班补卡'
                elif approval_row.end_datetime:
                    fill_card_hours += '下班补卡'
        if leave_all_hours:
            update_val.update({'leave_time': u'%s%s小时' % (leave_type_str, leave_all_hours)})
        if fill_card_hours:
            update_val.update({'fill_card': u'%s' % fill_card_hours})
        elif leave_type_str:
            update_val.update({'leave_time': u'%s%s小时' % (leave_type_str, leave_all_hours)})
        return copy.deepcopy(update_val)

    def get_punch_result(self, cr, uid, punch_row, default_val, date_str, context=None):
        """根据打卡记录 """
        update_val = {}
        timeArray = time.localtime((time.mktime(time.strptime(punch_row.date, '%Y-%m-%d %H:%M:%S')) + 8 * 3600))
        punch_row_date = time.strftime("%Y-%m-%d %H:%M:%S", timeArray)
        punch_rule_obj = self.pool.get('weixin.punch.rule')
        punch_rule_id = punch_rule_obj.search(cr, uid, [('name', '=', punch_row.groupname)], context=context)
        punch_timesamp = time.mktime(time.strptime(punch_row_date, '%Y-%m-%d %H:%M:%S'))
        if punch_rule_id:
            punch_rule_row = punch_rule_obj.browse(cr, uid, punch_rule_id[0], context=context)
            if punch_row.checkin_type == u'上班打卡':
                if punch_row.exception_type:
                    if punch_row.exception_type == u'未打卡':
                        update_val.update({'late_hours': u'上班未打卡'})
                    elif punch_row.exception_type == u'时间异常':
                        now_punch_date = '%s %s:00' % (punch_row_date[:10], punch_rule_row.begin_datetime)
                        punch_rule_timesamp = time.mktime(time.strptime(now_punch_date, '%Y-%m-%d %H:%M:%S'))
                        if punch_timesamp - punch_rule_timesamp > 0:
                            update_val.update(
                                {'late_hours': u'迟到%s' % self.get_time_to_str(float(punch_timesamp - punch_rule_timesamp))})
                    elif punch_row.exception_type == u'地点异常':
                        update_val.update({'late_hours': u'地点异常'})
                    else:
                        update_val.update({'late_hours': punch_row_date})
                else:
                    update_val.update({'late_hours': u'上班打卡正常'})
            elif punch_row.checkin_type == u'下班打卡':
                if punch_row.exception_type:
                    if punch_row.exception_type == u'未打卡':
                        update_val.update({'leave_early': u'下班未打卡'})
                    elif punch_row.exception_type == u'时间异常':
                        now_punch_date = '%s %s:00' % (punch_row_date[:10], punch_rule_row.end_datetime)
                        punch_rule_timesamp = time.mktime(time.strptime(now_punch_date, '%Y-%m-%d %H:%M:%S'))
                        if punch_rule_timesamp - punch_timesamp > 0:
                            update_val.update(
                                {'leave_early': u'早退%s' % self.get_time_to_str(float(punch_rule_timesamp - punch_timesamp))})
                    elif punch_row.exception_type == u'地点异常':
                        update_val.update({'leave_early': u'地点异常'})
                else:
                    update_val.update({'leave_early': u'下班打卡正常'})
            elif punch_row.checkin_type == u'外出打卡':
                punch_line_time_dict = default_val.get((date_str, punch_row.userid.odoo_user_id.id))
                if punch_line_time_dict and punch_line_time_dict.get('punch_line_time'):
                    update_val.update({'punch_line_time': '%s %s外勤打卡%s' % (punch_line_time_dict.get('punch_line_time'),
                                                                           punch_row_date,  punch_row.location_title)})
                else:
                    update_val.update({'punch_line_time': '%s外勤打卡%s' % (punch_row_date, punch_row.location_title)})
            else:
                if update_val.get('late_hours'):
                    update_val.update({'leave_early': punch_row_date})
                if update_val.get('leave_early'):
                    update_val.update({'late_hours': punch_row_date})
        elif punch_row.checkin_type == u'外出打卡':
            punch_line_time_dict = default_val.get((date_str, punch_row.userid.odoo_user_id.id))
            if punch_line_time_dict and punch_line_time_dict.get('punch_line_time'):
                update_val.update({'punch_line_time': '%s %s外勤打卡%s' % (punch_line_time_dict.get('punch_line_time'),
                                                                       punch_row_date, punch_row.location_title)})
            else:
                update_val.update({'punch_line_time': '%s外勤打卡%s' % (punch_row_date, punch_row.location_title)})
        elif punch_row.checkin_type == u'下班打卡':
            update_val.update({'leave_early': u'下班未打卡'})
        elif punch_row.checkin_type == u'上班打卡':
            update_val.update({'late_hours': u'上班未打卡'})
        return copy.deepcopy(update_val)

    def get_time_to_str(self, time_val):
        """
        根据时间戳的差值 得出更为明了的时间表示 时分的表示
        :param time_val: 时间戳的差值
        :return:
        """
        return_val = ''
        hours_vals = time_val//3600
        minu_vals = time_val % 3600//60
        if hours_vals:
            return_val += '%s小时' % hours_vals
        if minu_vals:
            return_val += '%s分钟' % minu_vals
        return return_val


class create_monthly_count_wizard(osv.osv):
    _name = 'create.monthly.count'
    _columns = {
        'begin_date': fields.date(u'日期', required=True),
        'filename_field': fields.char(u'文件名'),
        'data': fields.binary(u'文件', readonly=1),
    }
    _defaults = {
        'begin_date': False,
    }

    def create_monthly_count(self, cr, uid, ids, context=None):
        """
        根据每日的考勤的结果得出具体的 月考勤报表
        :return:
        """
        quant_obj = self.pool.get('recreate.quant')
        daily_count_obj = self.pool.get('daily.count')
        daily_count_wizard_obj = self.pool.get('create.daily.count.wizard')
        for monthly_row in self.browse(cr, uid, ids, context=context):
            begin_date, end_date = quant_obj.getMonthFirstDayAndLastDay(int(monthly_row.begin_date[:4]),
                                                                        int(monthly_row.begin_date[5:7]))
            begin_date = begin_date.strftime('%Y-%m-%d 00:00:00')
            end_date = end_date.strftime('%Y-%m-%d 23:59:59')
            wizard_id = daily_count_wizard_obj.create(cr, uid, {'begin_date': begin_date,
                                                                'end_date': end_date}, context=context)
            daily_count_wizard_obj.create_daily_count(cr, uid, wizard_id, context=context)
            month_day_count = calendar.monthrange(int(monthly_row.begin_date[:4]), int(monthly_row.begin_date[5:7]))[1]
            date_str = monthly_row.begin_date[:7]
            firstDay = datetime.date(year=int(monthly_row.begin_date[:4]), month=int(monthly_row.begin_date[5:7]),
                                     day=1)
            daily_ids = self.pool.get('daily.count').search(cr, uid, [('date', 'like', date_str)],
                                                            order='date, user_id', context=context)
            all_days = [(firstDay + datetime.timedelta(index)).strftime('%Y-%m-%d') for index in
                        xrange(month_day_count)]
            all_days.insert(0, '')
            all_messge_list = [[u'无记录' for i in range(len(all_days))]]
            all_messge_list[0] = all_days
            for daily_row in self.pool.get('daily.count').browse(cr, uid, daily_ids, context=context):
                if daily_row.user_id:
                    col_message = [x[0] for x in all_messge_list if x]
                    if daily_row.user_id and (
                        not col_message or (daily_row.user_id.id, daily_row.user_id.name) not in col_message):
                        all_messge_list.append([u'无记录' for i in range(len(all_days))])
                        all_messge_list[len(all_messge_list) - 1][0] = (daily_row.user_id.id, daily_row.user_id.name)

                    col_message = [x[0] for x in all_messge_list if x]
                    col_index = all_messge_list[0].index(daily_row.date)
                    row_index = col_message.index((daily_row.user_id.id, daily_row.user_id.name))
                    all_messge_list[row_index][col_index] = daily_row.result_message or u'  '
            xls = StringIO.StringIO()
            xls_workbook = xlwt.Workbook()
            data_sheet = xls_workbook.add_sheet(u'%s月考勤报表' % (monthly_row.begin_date[:4]), cell_overwrite_ok=True)
            data_sheet.row(0).height = 800
            for row in xrange(len(all_messge_list)):
                for col in xrange(len(all_messge_list[row])):
                    if col == 0 and row != 0:
                        message = all_messge_list[row][col][1]
                    else:
                        message = all_messge_list[row][col]
                    cell_style = self.get_cell_style(cr, uid, message, context=context)
                    data_sheet.write(row, col, message, cell_style)
            data_sheet.set_panes_frozen(True)  # frozen headings instead of split panes
            data_sheet.set_horz_split_pos(1)  # in general, freeze after last heading row
            data_sheet.set_vert_split_pos(1)  # in general, freeze after last heading row
            data_sheet.set_remove_splits(True)  # if user does unfreeze, don't leave a split there
            xls_workbook.save(xls)
            xls.seek(0)
            out = base64.encodestring(xls.getvalue())
            monthly_row.write({'data': out, 'filename_field': date_str + '考勤报表.xls'})
        return {
            'type': 'ir.actions.act_url',
            'url': '/web/binary/saveas?model=' + self._name + '&field=data&id=%s&filename_field=filename_field' % (
            ids[0]),
            'target': 'self',
        }

    def get_cell_style(self, cr, uid, message, context=None):
        """
        根据每个格子的内容来动态的显示excel 的样式
        :param message:
        :param context:
        :return:
        """
        crimson_style = xlwt.easyxf('align: wrap yes,vert centre, horiz center;pattern: pattern solid, \
                                               fore-colour yellow;border: left thin,right thin,top thin,bottom thin')
        base_style = xlwt.easyxf('align: wrap yes,vert centre, horiz left; pattern: pattern solid, \
                                                 fore-colour white;border: left thin,right thin,top thin,bottom thin')
        head_style = xlwt.easyxf('align: wrap yes,vert centre, horiz left; pattern: pattern solid, \
                                                 fore-colour white;border: left thin,right thin,top thin,bottom thin')
        gold_style = xlwt.easyxf('align: wrap yes,vert centre, horiz right ; pattern: pattern solid,\
                                                  fore-colour light_yellow;border: left thin,right thin,top thin,bottom thin')
        rose_style = xlwt.easyxf('align: wrap yes; pattern: pattern solid,fore-colour rose;border: left thin,right thin,top thin,bottom thin\
                                                 ')
        violet_style = xlwt.easyxf('align: wrap yes; pattern: pattern solid, fore-colour  sea_green;\
                                                     border: left thin,right thin,top thin,bottom thin')

        springgreen_style = xlwt.easyxf('align: wrap yes; pattern: pattern solid, fore-colour  dark_yellow;\
                                                    border: left thin,right thin,top thin,bottom thin')
        blue_style = xlwt.easyxf('align: wrap yes; pattern: pattern solid, fore-colour gray_ega;\
                                                     border: left thin,right thin,top thin,bottom thin')
        red_style = xlwt.easyxf('align: wrap yes; pattern: pattern solid, fore-colour red;\
                                                     border: left thin,right thin,top thin,bottom thin')
        if u'未打卡' in message:
            style = crimson_style
        elif u'缺卡' in message:
            style = gold_style
        elif u'调休' in message:
            style = rose_style
        elif u'请假' in message:
            style = violet_style
        elif u'补卡' in message:
            style = springgreen_style
        elif u'迟到' in message:
            style = red_style
        elif u'休息' in message:
            style = blue_style
        elif u'-' in message:
            style = head_style
        else:
            style = base_style
        return style